﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using System.Windows.Forms;

namespace RunAsLauncher
{
    public partial class MainForm : Form
    {
        // the args cache remembers the last argument you specified for a particular application path.
        // this is volatile. only the current value of txtArguments is persisted in settings.
        System.Collections.Specialized.StringDictionary argsCache;

        public MainForm()
        {
            InitializeComponent();
            argsCache = new System.Collections.Specialized.StringDictionary();
        }

        private void btnGo_Click(object sender, EventArgs e)
        {
            // do some basic field validation
            if (txtUsername.Text != string.Empty && txtPassword.Text != string.Empty && cmbxApplicationPath.Text != string.Empty)
            {
                try
                {
                    // save these settings now...just in case this utility crashes
                    SaveSettings();

                    try
                    {
                        char[] passwordChars = txtPassword.Text.ToCharArray();
                        System.Security.SecureString securePassword = new System.Security.SecureString();

                        foreach (char passChar in passwordChars)
                        {
                            securePassword.AppendChar(passChar);
                        }

                        string[] loginInfo = new string[2];
                        if (txtUsername.Text.Contains("\\"))
                        {
                            // username was entered with a domain prefix. split and use.
                            loginInfo = txtUsername.Text.Split('\\');
                        }
                        else
                        {
                            // username was not entered with a domain prefix. assume local machine. we can update the textbox to show that we're using this assumed value.
                            loginInfo[0] = Environment.MachineName;
                            loginInfo[1] = txtUsername.Text;
                            txtUsername.Text = string.Concat(loginInfo[0], "\\", loginInfo[1]);
                        }

                        ProcessStartInfo startInfo = new ProcessStartInfo(cmbxApplicationPath.Text);
                        startInfo.Domain = loginInfo[0];
                        startInfo.UserName = loginInfo[1];
                        startInfo.Password = securePassword;
                        startInfo.WindowStyle = ProcessWindowStyle.Normal;
                        startInfo.LoadUserProfile = chkLoadProfile.Checked;
                        startInfo.ErrorDialog = true;
                        startInfo.ErrorDialogParentHandle = this.Handle;
                        startInfo.UseShellExecute = false;

                        if (txtArguments.Text != string.Empty)
                        {
                            startInfo.Arguments = txtArguments.Text;
                        }

                        Process.Start(startInfo);

                        // make sure this application stays in the list and update the args cache
                        SaveApplicationPathToList();
                        UpdateArgsCache();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("Error: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error saving settings: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                
            }
            else
            {
                MessageBox.Show("You must fill in all fields. Arguments are optional.", "Incomplete Fields", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        private void btnChoose_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlgOpenFile = new OpenFileDialog();
            dlgOpenFile.Filter = "(*.exe)|*.exe";
            dlgOpenFile.DefaultExt = "exe";
            dlgOpenFile.CheckFileExists = true;
            dlgOpenFile.CheckPathExists = true;

            if (dlgOpenFile.ShowDialog(this) == DialogResult.OK)
            {
                cmbxApplicationPath.Text = dlgOpenFile.FileName;
                if (argsCache.ContainsKey(cmbxApplicationPath.Text))
                {
                    txtArguments.Text = argsCache[cmbxApplicationPath.Text];
                }
                else
                {
                    txtArguments.Text = string.Empty;
                }
            }
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            try
            {
                LoadSettings();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error loading settings: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void LoadSettings()
        {
            // this handles upgrades to the utility.
            // incrementing the assembly version will cause a new settings file to be created in the user's profile, so we need to tell the existing settings to carry over.
            if (Properties.Settings.Default.UpgradeRequired)
            {
                Properties.Settings.Default.Upgrade();
                Properties.Settings.Default.UpgradeRequired = false;
            }

            if (Properties.Settings.Default.LastUsername != null || Properties.Settings.Default.LastUsername != string.Empty)
                txtUsername.Text = Properties.Settings.Default.LastUsername;
            
            chkLoadProfile.Checked = Properties.Settings.Default.LastLoadProfile;

            // this is broken out into a separate method in case it is ever needed elsewhere (like in a settings management form).
            BuildApplicationPathList();

            txtArguments.Text = Properties.Settings.Default.LastArguments;

            if (cmbxApplicationPath.Items.Count > 0)
            {
                // start maintaining the args cache
                argsCache.Add((string)cmbxApplicationPath.Items[0], txtArguments.Text);
            }
        }

        private void BuildApplicationPathList()
        {
            if (Properties.Settings.Default.LastApplications.Count > 0)
            {
                foreach (string appPath in Properties.Settings.Default.LastApplications)
                {
                    cmbxApplicationPath.Items.Add(appPath);
                }

                cmbxApplicationPath.SelectedIndex = 0;
            }
        }

        private void SaveApplicationPathToList()
        {
            if (!cmbxApplicationPath.Items.Contains((string)cmbxApplicationPath.Text))
                cmbxApplicationPath.Items.Add(cmbxApplicationPath.Text);
        }

        private void SaveSettings()
        {
            if (txtUsername.Text != string.Empty)
                Properties.Settings.Default.LastUsername = txtUsername.Text;

            Properties.Settings.Default.LastLoadProfile = chkLoadProfile.Checked;

            // application path list
            if (Properties.Settings.Default.LastApplications.Count <= 10)
            {
                if (Properties.Settings.Default.LastApplications.Contains(cmbxApplicationPath.Text))
                {
                    Properties.Settings.Default.LastApplications.RemoveAt(Properties.Settings.Default.LastApplications.IndexOf(cmbxApplicationPath.Text));
                }
                Properties.Settings.Default.LastApplications.Insert(0, cmbxApplicationPath.Text);
            }
            else
            {
                if (Properties.Settings.Default.LastApplications.Contains(cmbxApplicationPath.Text))
                {
                    Properties.Settings.Default.LastApplications.RemoveAt(Properties.Settings.Default.LastApplications.IndexOf(cmbxApplicationPath.Text));
                }
                else
                {
                    Properties.Settings.Default.LastApplications.RemoveAt(9);
                }
                Properties.Settings.Default.LastApplications.Insert(0, cmbxApplicationPath.Text);
            }

            Properties.Settings.Default.LastArguments = txtArguments.Text;

            Properties.Settings.Default.Save();
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            SaveSettings();
        }

        private void cmbxApplicationPath_SelectedIndexChanged(object sender, EventArgs e)
        {
            RetrieveFromArgsCache();
        }

        private void UpdateArgsCache()
        {
            if (argsCache.ContainsKey(cmbxApplicationPath.Text))
                argsCache[cmbxApplicationPath.Text] = txtArguments.Text;
            else
                argsCache.Add(cmbxApplicationPath.Text, txtArguments.Text);
        }

        private void RetrieveFromArgsCache()
        {
            if (argsCache.ContainsKey((string)cmbxApplicationPath.Text))
            {
                txtArguments.Text = argsCache[(string)cmbxApplicationPath.Text];
            }
            else
            {
                txtArguments.Text = string.Empty;
            }
        }

        private void cmbxApplicationPath_TextUpdate(object sender, EventArgs e)
        {
            RetrieveFromArgsCache();
        }
        
    }
}
